﻿#include "../../libcat/include/cat-module.hpp"
#include "../../libcat/include/util/json.h"
#include "../../libcat/include/util/jsoncpp.cpp"

#include <string>
#include <corecrt_io.h>
#include <List>

#include <Mmsystem.h>
#include <mciapi.h>
//these two headers are already included in the <Windows.h> header
#pragma comment(lib, "Winmm.lib")

namespace {
	sf::Text textForLock;

	sf::Clock timer;
	sf::Clock timer2;

	long long count = 0;
	bool keys[256];
	int keyCountRecord[600];
	std::list<int> kpsRecord;

	unsigned int recordid = 0;
	int apm = 0;
	int last_apm = 0;
	

	std::vector<std::wstring> soundName;
}

const char* get_name() {
	return u8"APM";
}

void* Init(cat_data_t* settings) {

	textForLock.setFillColor(sf::Color(255, 255, 255));
	textForLock.setCharacterSize(30);
	textForLock.setPosition(sf::Vector2f(10, 0));

	soundName.clear();
	timer.restart();
	timer2.restart();
	count = 0;
	for (int i = 0; i < 256;i++) {
		keys[i] = false;
	}
	for (int i = 0; i < 600; i++) {
		keyCountRecord[i] = 0;
	}	
	return settings;
}

static bool isactive = false;

void* Update(cat_data_t* settings) {
	for (auto entry = settings->json["plugins"]["module"].begin(); entry != settings->json["plugins"]["module"].end(); entry++)
	{
		if ((*entry)["module_id"].asInt() == -3) {
			if (isactive != (*entry)["active"].asBool()) {
				isactive=(*entry)["active"].asBool();
				if (isactive)
				{
					Init(settings);
				}
			}
			break;
		}
	}	
	return settings;
}

void* Release() {

	count = 0;

	return NULL;
};

void* Run(void* _window) {
	cat_window* cwindow = (cat_window*)_window;

	int true_apm = 0;

	if (timer.getElapsedTime() > sf::seconds(0.2)) {
		timer.restart();
		if (recordid > 600)
			recordid = 0;

		keyCountRecord[recordid] = count;
		
		if (recordid < 5) {
			apm = keyCountRecord[recordid] - keyCountRecord[600 - (5 - recordid)];
		}
		else {
			apm = keyCountRecord[recordid] - keyCountRecord[recordid - 5];
		}

		if (apm < 0) {
			apm = 0;
		}
		kpsRecord.push_back(apm);
		for (auto ap = kpsRecord.begin(); ap != kpsRecord.end(); ap++)
			true_apm += (*ap);
		true_apm = static_cast<float>(true_apm) / static_cast<float>(kpsRecord.size())*60;
		last_apm = true_apm;
		if (kpsRecord.size() > 10)
			kpsRecord.pop_front();

		recordid++;
		
	}
	else {
		true_apm = last_apm;
	}
	textForLock.setFont(*cwindow->catfont);
	
	textForLock.setString("APM: "+std::to_string(true_apm));
	cwindow->window->draw(textForLock);
	return _window;
};

void* OnMouseClick(const cat_mouse_click_event* event, bool key_up)
{
	if (!key_up)
		count++;
	return NULL;
}

void* OnKeyPress(const cat_key_event* event, bool key_up)
{
	if (!keys[event->native_vkey]) {
		keys[event->native_vkey] = !key_up;
		count++;
	}
	else {
		keys[event->native_vkey] = !key_up;
	}
	return NULL;
}

CAT_DECLARE_MODULE()
bool cat_module_load (){
	cat_source_info rinbow {};
	rinbow.id = -2;
	rinbow.type = CAT_SOURCE_TYPE_UI;
	rinbow.Init = Init;
	rinbow.Update = Update;
	rinbow.Release = Release;
	rinbow.Run = Run;
	rinbow.get_name = get_name;
	rinbow.OnMouseClick = OnMouseClick;
	rinbow.OnKeyPress = OnKeyPress;

	cat_register_source(&rinbow);
	return true;
}
